function createElement(type, props, ...children) {
  return {
    type,
    props: {
      ...props,
      children: children.map((child) => {
        return typeof child === "object" ? child : createTextVDom(child);
      }),
    },
  };
}

function createTextVDom(text) {
  return {
    type: "TEXT",
    props: {
      nodeValue: text,
    },
  };
}
// 任务调度的全局变量
let workInProgressRoot = null;
let currentRoot = null;
let deletions = null;
let nextUnitOfWork = null;

// 调用render只是做初始化的工作
function render(vDom, container) {
  workInProgressRoot = {
    dom: container,
    props: {
      children: [vDom],
    },
    alternate: currentRoot,
  };
  //   收集要删除的节点
  deletions = [];
  //   设置下一个单元任务
  nextUnitOfWork = workInProgressRoot;
}

// workLoop用来调度任务
function workLoop(deadline) {
  while (nextUnitOfWork && deadline.timeRemaining() > 1) {
    // 这个while循环里执行任务，直到空闲时间结束
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
  }

  //任务做完后统一渲染
  if (!nextUnitOfWork && workInProgressRoot) {
    commitRoot();
  }

  //   如果任务还没完，但是时间到了，我们需要继续注册requestIdleCallback
  requestIdleCallback(workLoop);
  //   为了兼容低版本的浏览器，就会使用请求动画帧这个接口来模拟requestIdleCallback
  //   requestAnimationFrame()
}

// 在空闲时间就开始启动页面渲染
requestIdleCallback(workLoop);

// performUnitOfWork是用来执行任务，
function performUnitOfWork(fiber) {
  // 检查是否是函数组件
  const isFunctionComponent = fiber.type instanceof Function;
  if (isFunctionComponent) {
    updateFunctionComponent(fiber);
  } else {
    updateHostComponent(fiber);
  }

  //   这个函数的返回值是下一个任务，这是深度优先遍历
  //   先找子元素，没有子元素就找兄弟元素
  // 如果兄弟元素也没有，那么返回父元素
  // 再找这个父元素的兄弟元素
  // 最后返回到根节点结束、
  // 所以整个遍历的顺序就是从上到下，从左到右！

  if (fiber.child) {
    return fiber.child;
  }

  let nextFiber = fiber;
  while (nextFiber) {
    //   判断是否有兄弟元素
    if (nextFiber.sibling) {
      // 有兄弟元素就返回兄弟元素
      return nextFiber.sibling;
    }
    // 没有就返回上一层父元素，继续找父元素的兄弟元素
    nextFiber = nextFiber.return;
  }
}

function updateHostComponent(fiber) {
  if (!fiber.dom) {
    //   首先判断是否已经创建了一个DOM进行挂载，没有的话就进行创建
    fiber.dom = createDom(fiber);
  }

  //  将vDom结构转换成fiber结构
  const elements = fiber.props && fiber.props.child;

  //调和子元素
  reconcileChildren(fiber, elements);
}

function reconcileChildren(workInProgressRoot, elements) {
  // 构建fiber结构
  let oldFiber =
    workInProgressRoot.alternate && workInProgressRoot.alternate.fiber;
  let prevSibling = null;
  let index = 0;
  if (elements && elements.length && typeof elements != "string") {
    //   第一次是没有oldFiber
    if (!oldFiber) {
      for (let i = 0; i < elements.length; i++) {
        const element = elements[i];
        const newFiber = buildNewFiber(element, workInProgressRoot);
        // 父级的child指向第一个子元素
        if (i == 0) {
          workInProgressRoot.child = newFiber;
        } else {
          prevSibling.sibling = newFiber;
        }
        prevSibling = newFiber;
      }
    }
  }

  while (index < elements.length && oldFiber) {
    let element = elements[index];
    let newFiber = null;
    // 对比oldFiber和当前的element;
    const sameType = oldFiber && element && oldFiber.type === element.type;
    // 先比较元素类型，如果类型一样，那么复用节点，只需要更新
    if (sameType || typeof element != "object") {
      newFiber = {
        type: oldFiber,
        props:
          typeof element == "object" ? element.props : { nodeValue: element },
        dom: oldFiber.dom,
        return: workInProgressRoot,
        // 记录上一次的状态
        alternate: oldFiber,
        // 添加更新的标记任务
        effectTag: "UPDATE",
      };
    } else if (!sameType && element) {
      // 如果类型不一样，有新的节点，创建新的节点替换老节点
      newFiber = buildNewFiber(element, workInProgressRoot);
    } else if (!sameType && oldFiber) {
      // 如果类型不一样，没有新的节点，有老节点，删除老节点
      //   添加删除标记
      oldFiber.effectTag = "DELETION";
      deletions.push(oldFiber);
    }

    // 循环处理兄弟元素
    oldFiber = oldFiber.sibling;
    if (index == 0) {
      workInProgressRoot.child = newFiber;
    } else {
      prevSibling.sibling = newFiber;
    }
    prevSibling = newFiber;
    index++;
  }

  //   如果元素的类型是string类型，那么这个任务就按照string类型进行创建
}

function buildNewFiber(fiber, workInProgressRoot) {
  return {
    type: fiber.type ? fiber.type : "TEXT",
    props: fiber.props ? fiber.props : { nodeValue: fiber },
    // 构建fiber时时没有dom,下次perform这个节点才是创建DOM
    dom: null,
    // 设置返回至父元素的任务节点
    return: workInProgressRoot,
    // 新增的任务是没有老状态的
    alternate: null,
    // 添加一个操作标记
    effectTag: "REPLACEMENT",
  };
}

function useState() {}
export default {
  createElement,
  render,
  useState,
};
